Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / tests / backend / test_sticker_pack_utils.py

Displaying Raw • Download


tests/backend/test_sticker_pack_utils.py v4.6.0-rc.2 (7bbe9846) Text, 5.35 KB

T8b949e# SPDX-License-Identifier: 0BSD

T8b949e"""Unit tests for sticker pack document validation and sanitisation."""

Tff7b72import T7ee787base64

Tff7b72import T7ee787pytest

Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backend Tff7b72import Te6edf3sticker_pack_utils


Tff7b72def Td2a8fftest_sanitize_pack_title_defaultTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_titleTb4b4b4(Tff7b72NoneTb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffUntitled packTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_titleTb4b4b4(Ta5d6ff"Ta5d6ff Ta5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffUntitled packTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_titleTb4b4b4(Ta5d6ff"Ta5d6ff hello Ta5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffhelloTa5d6ff"
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_titleTb4b4b4(Ta5d6ff"Ta5d6ffxTa5d6ff" Tff7b72* T79c0ff500Tb4b4b4)Tb4b4b4) Tff7b72== T79c0ff80


Tff7b72def Td2a8fftest_sanitize_pack_short_nameTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_short_nameTb4b4b4(Tff7b72NoneTb4b4b4) Tff7b72is Tff7b72None
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_short_nameTb4b4b4(Ta5d6ff"Ta5d6ffCats!@#Ta5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffcatsTa5d6ff"
Tff7b72assert Tb4b4b4(
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_short_nameTb4b4b4(Ta5d6ff"Ta5d6ff Hello_World-1 Ta5d6ff"Tb4b4b4)
Tff7b72== Ta5d6ff"Ta5d6ffhello_world-1Ta5d6ff"
Tb4b4b4)
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_short_nameTb4b4b4(Ta5d6ff"Ta5d6ff***Ta5d6ff"Tb4b4b4) Tff7b72is Tff7b72None
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_short_nameTb4b4b4(Ta5d6ff"Ta5d6ffaTa5d6ff" Tff7b72* T79c0ff200Tb4b4b4)Tb4b4b4) Tff7b72== T79c0ff32


Tff7b72def Td2a8fftest_sanitize_pack_descriptionTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_descriptionTb4b4b4(Tff7b72NoneTb4b4b4) Tff7b72is Tff7b72None
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_descriptionTb4b4b4(Ta5d6ff"Ta5d6ff Ta5d6ff"Tb4b4b4) Tff7b72is Tff7b72None
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_descriptionTb4b4b4(Ta5d6ff"Ta5d6ff hiTffea00\nTa5d6ffthere Ta5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffhiTffea00\nTa5d6ffthereTa5d6ff"
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_descriptionTb4b4b4(Ta5d6ff"Ta5d6ffxTa5d6ff" Tff7b72* T79c0ff1000Tb4b4b4)Tb4b4b4) Tff7b72== T79c0ff280


Tff7b72def Td2a8fftest_sanitize_pack_typeTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Tff7b72NoneTb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffmixedTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Ta5d6ff"Ta5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffmixedTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Ta5d6ff"Ta5d6ffstaticTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffstaticTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Ta5d6ff"Ta5d6ffANIMATEDTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffanimatedTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Ta5d6ff"Ta5d6ffVIDEOTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffvideoTa5d6ff"
Tff7b72assert Te6edf3sticker_pack_utilsTff7b72.Td2a8ffsanitize_pack_typeTb4b4b4(Ta5d6ff"Ta5d6ffgarbageTa5d6ff"Tb4b4b4) Tff7b72== Ta5d6ff"Ta5d6ffmixedTa5d6ff"


Tff7b72def Td2a8fftest_build_pack_document_shapeTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3pack Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff My Pack Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMyPack!Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffdescTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffpack_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffstaticTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffauthorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffaliceTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffis_strictTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}
Te6edf3doc Tff7b72= Te6edf3sticker_pack_utilsTff7b72.Td2a8ffbuild_pack_documentTb4b4b4(Te6edf3packTb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ff2026-01-01T00:00:00ZTa5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4] Tff7b72== T79c0ff1
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffMy PackTa5d6ff"
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffmypackTa5d6ff"
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffstaticTa5d6ff"
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffauthorTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffaliceTa5d6ff"
Tff7b72assert Te6edf3docTb4b4b4[Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4] Tff7b72== Tb4b4b4[Tb4b4b4]


Tff7b72def Td2a8fftest_validate_pack_document_okTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3b64 Tff7b72= Te6edf3base64Tff7b72.Td2a8ffb64encodeTb4b4b4(Ta5d6ffbTa5d6ff"Tffea00\x89Ta5d6ffPNGTffea00\rTffea00\nTffea00\x1aTffea00\nTa5d6ff" Tff7b72+ Ta5d6ffbTa5d6ff"Tffea00\x00Ta5d6ff" Tff7b72* T79c0ff8Tb4b4b4)Tff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffasciiTa5d6ff"Tb4b4b4)
Te6edf3doc Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffCatsTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffshort_nameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffcatsTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdescriptionTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6fftypeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffstaticTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffauthorTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Ta5d6ff"Ta5d6ffis_strictTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[
Tb4b4b4{Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffkittenTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffemojiTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffcatTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffimage_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffpngTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffimage_bytesTa5d6ff"Tb4b4b4: Te6edf3b64Tb4b4b4}Tb4b4b4,
Tb4b4b4]Tb4b4b4,
Tb4b4b4}
Te6edf3out Tff7b72= Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(Te6edf3docTb4b4b4)
Tff7b72assert Te6edf3outTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffCatsTa5d6ff"
Tff7b72assert Te6edf3outTb4b4b4[Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffpack_typeTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffstaticTa5d6ff"
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3outTb4b4b4[Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4]Tb4b4b4) Tff7b72== T79c0ff1
Tff7b72assert Te6edf3outTb4b4b4[Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4]Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffimage_bytes_b64Ta5d6ff"Tb4b4b4] Tff7b72== Te6edf3b64
Tff7b72assert Te6edf3outTb4b4b4[Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4]Tb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffemojiTa5d6ff"Tb4b4b4] Tff7b72== Ta5d6ff"Ta5d6ffcatTa5d6ff"


Tff7b72def Td2a8fftest_validate_pack_document_wrong_formatTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffinvalid_pack_formatTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffotherTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4, Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4, Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[Tb4b4b4]Tb4b4b4}Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_unsupported_versionTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffunsupported_pack_versionTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff99Tb4b4b4,
Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_not_dictTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffinvalid_pack_documentTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(Tb4b4b4[Tb4b4b4]Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_missing_metaTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffinvalid_pack_metaTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4, Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[Tb4b4b4]Tb4b4b4}Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_bad_stickersTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffinvalid_pack_stickersTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffnoTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_bad_sticker_entryTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffinvalid_pack_sticker_at_0Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[Ta5d6ff"Ta5d6ffnopeTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)


Tff7b72def Td2a8fftest_validate_pack_document_missing_bytesTb4b4b4(Tb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3pytestTff7b72.Td2a8ffraisesTb4b4b4(Tf85149ValueErrorTb4b4b4, Te6edf3matchTff7b72=Ta5d6ff"Ta5d6ffmissing_pack_sticker_bytes_at_0Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3sticker_pack_utilsTff7b72.Td2a8ffvalidate_pack_documentTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffformatTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshchatx-stickerpackTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffversionTa5d6ff"Tb4b4b4: T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffpackTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffstickersTa5d6ff"Tb4b4b4: Tb4b4b4[Tb4b4b4{Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffxTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffimage_typeTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffpngTa5d6ff"Tb4b4b4}Tb4b4b4]Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────